﻿using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SimbaRGVMonitor.Views.Components
{
    abstract class ArrowBase : Shape
    {
        protected ArrowBase()
        {
            InitializeSettings();
        }

        //====================================================================================================
        //以上是类型构造函数
        //----------------------------------------------------------------------------------------------------
        //以下是类型字段
        //====================================================================================================

        private readonly PathFigure figureEnd = new PathFigure();
        private readonly PathFigure figureStart = new PathFigure();
        private readonly PathFigure figureConcrete = new PathFigure();
        private readonly PathGeometry geometryWhole = new PathGeometry();
        private readonly PathGeometry geometryConcrete = new PathGeometry();
        public static readonly DependencyProperty ArrowAngleProperty = DependencyProperty.Register("ArrowAngle", typeof(double), typeof(ArrowBase), new FrameworkPropertyMetadata(45.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
        public static readonly DependencyProperty ArrowLengthProperty = DependencyProperty.Register("ArrowLength", typeof(double), typeof(ArrowBase), new FrameworkPropertyMetadata(12.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
        public static readonly DependencyProperty ArrowEndsProperty = DependencyProperty.Register("ArrowEnds", typeof(ArrowEnds), typeof(ArrowBase), new FrameworkPropertyMetadata(ArrowEnds.End, FrameworkPropertyMetadataOptions.AffectsMeasure));
        public static readonly DependencyProperty IsArrowClosedProperty = DependencyProperty.Register("IsArrowClosed", typeof(bool), typeof(ArrowBase), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure));
        public static readonly DependencyProperty StartPointProperty = DependencyProperty.Register("StartPoint", typeof(Point), typeof(ArrowBase), new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsMeasure));
        public static readonly DependencyProperty ArrowGeometryConcreteProperty = DependencyProperty.Register("ArrowGeometryConcrete", typeof(PathGeometry), typeof(ArrowBase), new FrameworkPropertyMetadata(default(PathGeometry), FrameworkPropertyMetadataOptions.AffectsMeasure));

        //====================================================================================================
        //以上是类型字段
        //----------------------------------------------------------------------------------------------------
        //以下是类型属性
        //====================================================================================================

        public double ArrowAngle
        {
            get { return (double)GetValue(ArrowAngleProperty); }
            set { SetValue(ArrowAngleProperty, value); }
        }

        public double ArrowLength
        {
            get { return (double)GetValue(ArrowLengthProperty); }
            set { SetValue(ArrowLengthProperty, value); }
        }

        public ArrowEnds ArrowEnds
        {
            get { return (ArrowEnds)GetValue(ArrowEndsProperty); }
            set { SetValue(ArrowEndsProperty, value); }
        }

        public bool IsArrowClosed
        {
            get { return (bool)GetValue(IsArrowClosedProperty); }
            set { SetValue(IsArrowClosedProperty, value); }
        }

        public Point StartPoint
        {
            get { return (Point)GetValue(StartPointProperty); }
            set { SetValue(StartPointProperty, value); }
        }

        public PathGeometry ArrowGeometryConcrete
        {
            get { return geometryConcrete; }
        }

        protected override Geometry DefiningGeometry
        {
            get
            {
                figureConcrete.StartPoint = StartPoint;
                figureConcrete.Segments.Clear();

                var segements = FillFigure();
                if (segements != null)
                {
                    foreach (var segement in segements)
                    {
                        figureConcrete.Segments.Add(segement);
                    }
                }

                if ((ArrowEnds & ArrowEnds.Start) == ArrowEnds.Start)
                {
                    var endPoint = GetStartArrowEndPoint();
                    CalculateArrow(figureStart, endPoint, StartPoint);
                }

                if ((ArrowEnds & ArrowEnds.End) == ArrowEnds.End)
                {
                    var endPoint = GetEndArrowEndPoint();
                    var startPoint = GetEndArrowStartPoint();
                    CalculateArrow(figureEnd, startPoint, endPoint);
                }

                return geometryWhole;
            }
        }

        //====================================================================================================
        //以上是类型属性
        //----------------------------------------------------------------------------------------------------
        //以下是初始化设置
        //====================================================================================================

        private void InitializeSettings()
        {
            var polyLineSegStart = new PolyLineSegment();
            figureStart.Segments.Add(polyLineSegStart);

            var polyLineSegEnd = new PolyLineSegment();
            figureEnd.Segments.Add(polyLineSegEnd);

            geometryConcrete.Figures.Add(figureConcrete);

            geometryWhole.Figures.Add(figureConcrete);
            geometryWhole.Figures.Add(figureStart);
            geometryWhole.Figures.Add(figureEnd);
        }

        //====================================================================================================
        //以上是初始化设置
        //----------------------------------------------------------------------------------------------------
        //以下是抽象函数
        //====================================================================================================

        protected abstract Point GetEndArrowEndPoint();
        protected abstract Point GetEndArrowStartPoint();
        protected abstract Point GetStartArrowEndPoint();
        protected abstract PathSegmentCollection FillFigure();

        //====================================================================================================
        //以上是抽象函数
        //----------------------------------------------------------------------------------------------------
        //以下是计算箭头
        //====================================================================================================

        private void CalculateArrow(PathFigure pathfig, Point startPoint, Point endPoint)
        {
            var polyseg = pathfig.Segments[0] as PolyLineSegment;
            if (polyseg != null)
            {
                var matx = new Matrix();
                Vector vect = startPoint - endPoint;

                vect.Normalize();
                vect *= this.ArrowLength;

                matx.Rotate(ArrowAngle / 2);

                pathfig.StartPoint = endPoint + (vect * matx);

                polyseg.Points.Clear();
                polyseg.Points.Add(endPoint);

                matx.Rotate(-1 * ArrowAngle);

                polyseg.Points.Add(endPoint + (vect * matx));
            }

            pathfig.IsClosed = IsArrowClosed;
        }
    }
}
